simple crackme
password validation with basic obfuscation
Another binary with XOR encryption, straightforward this time. The actual password is encrypted and 10 characters long. It is decrypted in the background, and the plaintext version is passed to the string comparison against whatever the user typed. The flag, 22 characters long, is also XOR decrypted using a changing key once the correct password is entered.
Patching the Binary
On running the binary i got this error straight away:
./crackme: CPU ISA level is lower than required
This happens when a binary is compiled targeting a newer x86-64 feature level (v2, v3, or v4) than what the host CPU supports. The feature level requirement is encoded in the ELF file, and if the CPU does not meet it, the dynamic linker refuses to load the binary. Fix is patching that requirement byte in the ELF header down to a level the CPU does support. I did this crackme a couple of weeks ago and I don't remember the exact method I used at the time, but after patching, the binary ran fine.
What tripped me up was reading the encrypted password bytes correctly. This is how it appeared in the disassembly:
db 27h,'(",-6:',27h,'(",',0
Lesson: 27h is the hex value for a single quote ' in ASCII. When you see something like '(",-6:' in assembly data definitions, the single quotes are IDA's way of showing printable characters inline, they are not part of the actual string. You take only what is inside them. The trailing 0 is the null terminator. So the encrypted password is exactly 10 bytes: '(",-6:'(",.
Decryption Loop

The loop counter starts at zero and is loaded into eax, then cdqe (Convert Double Word to Quad Word) sign-extends it from 4 bytes to 8 bytes (eax to rax). This is necessary for address arithmetic since the pointer to the encrypted message is 64-bit, the index register needs to match that width.
The address of the encrypted message is loaded into rdx. The current character is read via movzx edx, byte ptr [rax+rdx], that is enc_msg[i], zero-extended into the full register. The XOR key 0x69 is loaded into ecx, and xor ecx, eax decrypts the character. The result is written back to [rax+rdx], overwriting the encrypted byte with the decrypted one in place. The counter increments and the loop runs 10 times.
Setting a breakpoint mid-loop confirms this. RAX holds 0x69 = the key, and RDX holds 0x27, which is the single quote character ', the first byte of the encrypted message.

The encrypted message '(",-6:'(", decrypts with key 0x69 to NAKED_SNAKE.
Flag Keygen and Password Comparison

The flag key is generated by XOR-ing two values the binary author labelled multiplier and offset. From the registers we can see RAX = 0xBB after the multiplier is loaded, and the XOR with offset produces 0xB8, which is the base key used to decrypt the flag.

The input is then compared against the decrypted password via strcmp. If it does not match the program prints wrong password, try again. and drops back to a > prompt, looping through scanf again to give the user another attempt.

If the passwords match, the zero flag is set and execution proceeds to the flag decryption path.
Happy Path

Once the correct password is entered, the program checks the input length against 0x16 (22) and branches into the flag decryption loop on the right. The ecnrypted flag bytes are EFF7FEC7FCFBF5FE and the loop runs 22 times, XOR-ing each encrypted flag byte with an incrementing key, starting at 0xB8 and increasing by 1 each round. After decryption, _puts prints the flag to the terminal. The stack canary is then checked and if it's intact, the function returns cleanly.


